package hoja3;
/*666666666666666666666666666666666666666666666
 * 				Banco
 * 
 * Esrcito por: Ernesto Rodriguez
 * 
 * Simula las colas de un banco mediante la
 * estructura de datos conocida como cola.
 666666666666666666666666666666666666666666666*/

import java.util.*;


public class Banco {


	Cola <Cliente> [] colas;
	Lista <Evento> eventos;
	int globaltime = 0;
	Random nums = new Random();
	int total = 0;
	int cuates=0;
	
	/**
	 * Inicializa el banco. Esto consiste en crear las colas
	 * donde estaran los clientes y la lista de eventos. Un 
	 * programador puede escoger implementar las colas
	 * mediante listas o arreglos.
	 * @author gallo
	 *
	 */
	public Banco(){
		
		colas = new Cola[4];
		eventos = new ImplementacionHashMap<Evento>();
		
		//Se puede escoger implementar la cola mediante
		//arreglos o listas
		for (int veces=0; veces<colas.length; veces++)
			colas[veces]= new colaArreglo<Cliente>(10);
			//colas[veces]= new colaLista<Cliente>(10);
	}
	
	/**
	 * Agrega un evento a la lista de eventos. Este metodo
	 * se encarga de agragar el evento en la posicion correcta
	 * en referencia al tiempo en el que debe ejecutarse el evento
	 * de manera que los eventos se ejecuten de forma ordenada
	 * 
	 * @param env El evento que desea agregarse a la lista
	 */
	public void addEvent(Evento env){
		
		eventos.reset();
		int veces=0;
		//System.out.println("geelawee");
		while(eventos.hasNext()){
			
			
			if(eventos.next().getTiempo()>env.getTiempo()){
				eventos.add(env, veces);
				//System.out.println(eventos);
				return;
			}
			
			veces++;
			//System.out.println(veces++);
		}
		
		//System.out.println("fail");
		eventos.add(env);
		//System.out.println(eventos);
	}
	
	/**
	 * Este metodo ejecuta el siguiente evento en la lista
	 * de eventos. Esta lista esta ordenada segun el orden
	 * en que los eventos deben ser ejecutados.
	 */
	
	public void execEvento(){
		
		//System.out.println(eventos.toString());
		
		Evento evn = eventos.get(0);
		eventos.delete(0);
		globaltime= evn.getTiempo();
		//globaltime=10;
		
		if(evn.getTipo()){
			try{
				addCuate(evn.getTiempo(),nums.nextInt(31)+1);
				System.out.println("Llega Cliente");
				cuates++;
			}catch(ArrayIndexOutOfBoundsException e){
				
				System.out.println("Llega cliente, banco lleno");
				//throw e;
			}
		}
		else{
			quitarCuate(evn.getCola());
			System.out.println("Sale Cliente");
		}
		
		System.out.println("Momento del Evento: " + globaltime);
		System.out.println("------------------------------------");
		
		//System.out.println("Cola 1: ");
		//for (int veces=0; veces<colas[]);
		
		for (int veces=0; veces<colas.length; veces++){
			
			System.out.print("Cola " + veces + ": ");
			for (int veces1=0; veces1<colas[veces].size(); veces1++)
				System.out.print("#");
			
			System.out.println();
		}
			
		System.out.println("------------------------------------");
	}
	
	/**
	 * Este metodo agrega un cliente a la cola. Tambien se encarga
	 * de agregar un evento de remocion a la lista de eventos si 
	 * el cliente agregado es el unico en la cola. Este metodo
	 * es llamado cuando se acciona un evento de adicion de un cliente.
	 * 
	 * @param tiempo El momento en que fue accionado el evento.
	 * @param duracion La duracion de la transaccion del cliente.
	 */
	
	private void addCuate(int tiempo, int duracion){
		
		int shortest=0;
		for(int veces=0; veces<colas.length; veces++){
			
			if(colas[shortest].size()>colas[veces].size())
				shortest=veces;
		}
		
		//System.out.println("Geeelawee");
		colas[shortest].add(new Cliente(tiempo, duracion));
		
		//System.out.println("Geeelawee");
		if (colas[shortest].size()==1){
			//System.out.println("Geeelawee");
			addEvent(new Evento(shortest, globaltime+duracion));
		
		}
		
	}
	/**
	 * Este metodo remueve a un cliente de la cola luego de
	 * que ha terminado su transaccion. Este metodo se encarga
	 * de agregar un evento de remocion a la lista de eventos
	 * para el siguiente cliente en la cola. Este metodo es 
	 * llamado cuando se produce un evento de remocion de
	 * cliente
	 * 
	 * @param lugar Cola de la cual debe removerse el cliente
	 */
	private void quitarCuate(int lugar){
		
		total = total + (-colas[lugar].next().getTiempo() + globaltime);
		
		if(colas[lugar].size()==0)
			return;
		
		addEvent(new Evento(lugar, colas[lugar].look().getDuracion()+globaltime));
		//System.out.println(eventos);
	}

	/**
	 * Indica Si aun quedan eventos o no en la lista de eventos
	 * 
	 * @returnn True si ya no hay eventos en la lista.
	 */
	public boolean hasEvent(){
		
		//System.out.println("Q onda " + eventos.size());
		
		if (eventos.size()==0)
			return false;
		
		return true;
	}
	
	/**
	 * Permite saber el tiempo promedio que un cliente estuvo en la cola
	 * 
	 * @return Tiempo promedio de un cliente en la cola
	 */
	
	public int getTotal(){
		
		return total/cuates;
	}
}
